package info.thereisonlywe.core.essentials;

import info.thereisonlywe.core.essentials.EsotericEssentials.Planet;
import info.thereisonlywe.core.essentials.StringEssentials.Characters.Arabic;

import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 
 * @author thereisonlywe
 */
public class StringEssentials {

	public static class Characters {

		public static class Arabic {

			public static String SHADDA = "\u0651";
			public static String KASRA = "\uFE7A";
			public static String DAMMA = "\uFE78";
			public static String FATHA = "\uFE76";
			public static String SUKUN = "\u0652";
			public static String KASRATAN = "\uFE74";
			public static String DAMMATAN = "\uFE72";
			public static String FATHATAN = "\uFE70";
			public static String MADDAH = "\u0653";
			public static String ALEPH_SUPERSCRIPT = "\u0670";
			public static String ALEPH_WASLA = "\u0671";
			public static String ALEPH = "\u0627";
			public static String HAMZA_ABOVE = "\u0654";
			public static String HAMZA_BELOW = "\u0655";
			public static String HAMZA = "\u0621";
			public static final String COMPULSORY_PAUSE_QURAN_PAUSE_MARK = "\u06D8";
			public static final String IMPERMISSIBLE_PAUSE_QURAN_PAUSE_MARK = "\u06D9";
			public static final String PERMISSIBLE_PAUSE_QURAN_PAUSE_MARK = "\u06DA";
			public static final String UNPREFERABLE_PAUSE_QURAN_PAUSE_MARK = "\u06D6";
			public static final String PREFERABLE_PAUSE_QURAN_PAUSE_MARK = "\u06D7";
			public static final String INTERCHANGEABLE_PAUSE_QURAN_PAUSE_MARK = "\u06DB";

			public static boolean isDamma(char c)
			{
				if (c == DAMMA.charAt(0)) { return true; }
				return false;
			}

			public static boolean isDammatan(char c)
			{
				if (c == DAMMATAN.charAt(0)) { return true; }
				return false;
			}

			public static boolean isDiacriticMark(char c)
			{
				if (isMaddah(c) || isFatha(c) || isKasra(c) || isDamma(c)
						|| isSukun(c) || isShadda(c) || isFathatan(c)
						|| isKasratan(c) || isDammatan(c)) { return true; }
				return false;
			}

			public static boolean isFatha(char c)
			{
				if (c == FATHA.charAt(0)) { return true; }
				return false;
			}

			public static boolean isFathatan(char c)
			{
				if (c == FATHATAN.charAt(0)) { return true; }
				return false;
			}

			public static boolean isKasra(char c)
			{
				if (c == KASRA.charAt(0)) { return true; }
				return false;
			}

			public static boolean isKasratan(char c)
			{
				if (c == KASRATAN.charAt(0)) { return true; }
				return false;
			}

			public static boolean isMaddah(char c)
			{
				if (c == MADDAH.charAt(0)) { return true; }
				return false;
			}

			public static boolean isQuranicPauseMark(char c)
			{
				if (c == COMPULSORY_PAUSE_QURAN_PAUSE_MARK.charAt(0)
						|| c == IMPERMISSIBLE_PAUSE_QURAN_PAUSE_MARK.charAt(0)
						|| c == UNPREFERABLE_PAUSE_QURAN_PAUSE_MARK.charAt(0)
						|| c == PREFERABLE_PAUSE_QURAN_PAUSE_MARK.charAt(0)
						|| c == PERMISSIBLE_PAUSE_QURAN_PAUSE_MARK.charAt(0)
						|| c == INTERCHANGEABLE_PAUSE_QURAN_PAUSE_MARK
								.charAt(0))
				{
					return true;
				}
				else
				{
					return false;
				}
			}

			public static boolean isShadda(char c)
			{
				if (c == SHADDA.charAt(0)) { return true; }
				return false;
			}

			public static boolean isSukun(char c)
			{
				if (c == SUKUN.charAt(0)) { return true; }
				return false;
			}

			public static boolean isValid(char c)
			{
				if (Character.UnicodeBlock.of(c).equals(
						Character.UnicodeBlock.ARABIC))
				{
					return true;
				}
				else
				{
					return false;
				}
			}

		}

		public static class Logic {
			public static String NOT2 = "\u00ac";
			public static String NOT = "\u02dc";
			public static String AND = "\u2227";
			public static String AND2 = "\u0026";
			public static String OR = "\u2228";
			public static String XOR = "\u2295";
			public static String XOR2 = "\u22bb";
			public static String NAND = "\u22BC";

			public static boolean isConjunctionChar(char c)
			{
				if (c == AND.charAt(0) || c == AND2.charAt(0)) { return true; }
				return false;
			}

			public static boolean isConjunctionNegationChar(char c)
			{
				if (c == NAND.charAt(0)) { return true; }
				return false;
			}

			public static boolean isDisjunctionChar(char c)
			{
				if (c == OR.charAt(0)) { return true; }
				return false;
			}

			public static boolean isExclusiveDisjunctionChar(char c)
			{
				if (c == XOR.charAt(0) || c == XOR2.charAt(0)) { return true; }
				return false;
			}

			public static boolean isNegationChar(char c)
			{
				if (c == NOT.charAt(0) || c == NOT2.charAt(0)) { return true; }
				return false;
			}
		}

		public static class Symbol {
			public static String MOON = "\u263D";
			public static String SUN = "\u2609";
			public static String MERCURY = "\u263F";
			public static String VENUS = "\u2640";
			public static String MARS = "\u2642";
			public static String JUPITER = "\u2643";
			public static String SATURN = "\u2644";
			public static String NORTH_NODE = "\u260A";
			public static String SOUTH_NODE = "\u260B";

			public static String getPlanetSymbol(Planet p)
			{
				if (p.equals(Planet.SATURN))
				{
					return SATURN;
				}
				else if (p.equals(Planet.JUPITER))
				{
					return JUPITER;
				}
				else if (p.equals(Planet.MARS))
				{
					return MARS;
				}
				else if (p.equals(Planet.SUN))
				{
					return SUN;
				}
				else if (p.equals(Planet.VENUS))
				{
					return VENUS;
				}
				else if (p.equals(Planet.MERCURY))
				{
					return MERCURY;
				}
				else if (p.equals(Planet.MOON))
				{
					return MOON;
				}
				else if (p.equals(Planet.NORTH_NODE))
				{
					return NORTH_NODE;
				}
				else if (p.equals(Planet.SOUTH_NODE))
				{
					return SOUTH_NODE;
				}
				else
				{
					return null;
				}
			}
		}

		public static final String LINE_SEPARATOR = ")|(";

		public static final String VALUE_SEPARATOR = "#:#";
	}

	public static String arrayToString(String s[])
	{
		String result = s[0];
		for (int i = 1; i < s.length; i++)
		{
			result += "\n" + s[i];
		}
		return result;
	}

	public static int caretPositionToWordPosition_AR(int caret, String text)
	{
		int count = 1;
		int len = text.length();
		if (caret < text.length())
		{
			len = caret;
		}
		for (int i = 0; i < len; i++)
		{
			if (text.charAt(i) == ' ')
			{
				count++;
			}
			else if (text.charAt(i) == 'ۘ' || text.charAt(i) == 'ۙ'
					|| text.charAt(i) == 'ۚ' || text.charAt(i) == 'ۗ'
					|| text.charAt(i) == 'ۖ' || text.charAt(i) == 'ۛ')
			{
				count--;
			}
		}
		return count;
	}

	public static boolean contains(String array[], String s)
	{
		for (final String element : array)
		{
			if (element.equals(s)) { return true; }
		}
		return false;
	}

	public static String capitalizeFirst(String s, Locale locale)
	{
		String[] words = splitWords(s);
		for (int i = 0; i < words.length; i++)
		{
			words[i] = (locale == null ? new String(words[i].charAt(0) + "")
					.toUpperCase() : new String(words[i].charAt(0) + "")
					.toUpperCase(locale))
					+ new String(words[i].substring(1));
		}
		return glue(words, " ");
	}

	public static String capitalizeFirst(String s)
	{
		return capitalizeFirst(s, null);
	}

	public static boolean containsCharacter(String s, Character.UnicodeBlock u)
	{
		for (int l = 0; l < s.length(); l++)
		{
			if (Character.UnicodeBlock.of(s.charAt(l)).equals(u)) { return true; }
		}
		return false;
	}

	public static String createHTMLString(String[] parts)
	{
		final StringBuilder sb = new StringBuilder();
		sb.append("<html><table><tr>");
		for (final String part : parts)
		{
			sb.append("<td>");
			sb.append(part);
			sb.append("</td>");
		}
		sb.append("</tr></table></html>");
		return sb.toString();
	}

	public static ArrayList<String> cut(String s, String separator)
	{
		return new ArrayList<String>(Arrays.asList(s.split(separator)));
	}

	public static String enclose(String s, char charToBeEnclosed,
			char charToEncloseWith)
	{
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			final char c = s.charAt(i);
			if (c == charToBeEnclosed)
			{
				sb.append(charToEncloseWith);
				sb.append(charToBeEnclosed);
				sb.append(charToEncloseWith);
			}
			else
			{
				sb.append(c);
			}
		}
		return sb.toString();
	}

	public static String fetchDelimitedEntry(String s, char delimiter,
			int entryNo)
	{
		for (int i = 1; i < entryNo; i++)
		{
			s = new String(s.substring(s.indexOf(delimiter) + 1));
		}

		if (s.contains("" + delimiter))
		{
			s = new String(s.substring(0, s.indexOf(delimiter)));
		}
		return s;
	}

	public static String free(String s, char enclosedChar, char enclosingChar)
	{
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			final char c = s.charAt(i);
			if (c == enclosingChar && i < s.length() - 2
					&& s.charAt(i + 1) == enclosedChar
					&& s.charAt(i + 2) == enclosingChar)
			{
				sb.append(enclosedChar);
				i += 2;
			}
			else
			{
				sb.append(c);
			}
		}
		return sb.toString();
	}

	public static int getBlanksUpTo(int caret, String text)
	{
		int count = 0;
		for (int i = 0; i < caret; i++)
		{
			if (text.charAt(i) == ' ')
			{
				count++;
			}
		}
		return count;
	}

	public static int getIndexOfNextBlank(int caret, String text)
	{
		for (int i = caret + 1; i < text.length(); i++)
		{
			if (text.charAt(i) == ' ') { return i; }
		}
		return -1;
	}

	public static int getIndexOfNthWord(int n, String s)
	{
		for (int i = 0; i < s.length(); i++)
		{
			if (getBlanksUpTo(i, s) == n - 1) { return i; }
		}
		return -1;
	}

	public static int getIndexOfPreviousBlank(int caret, String text)
	{
		for (int i = caret; i >= 0; i--)
		{
			if (text.charAt(i) == ' ') { return i; }
		}
		return -1;
	}

	public static int getNumberOfDiacritics(String s)
	{
		int count = 0;
		for (int i = 0; i < s.length(); i++)
		{
			if (Arabic.isDiacriticMark(s.charAt(i)))
			{
				count++;
			}
		}
		return count;
	}

	public static int getNumberOfPauseMarks_AR(String text)
	{
		int counter = 0;
		for (int i = 0; i < text.length(); i++)
		{
			if (isPauseMark_AR(text.charAt(i)))
			{
				counter++;
			}
		}
		return counter;
	}

	public static String glue(ArrayList<String> s, String separator)
	{
		final StringBuilder result = new StringBuilder();
		for (int i = 0; i < s.size() - 1; i++)
		{
			result.append(s.get(i));
			result.append(separator);
		}
		result.append(s.get(s.size() - 1));
		return result.toString();
	}

	public static String glue(int[] s, String separator)
	{
		final StringBuilder result = new StringBuilder();
		for (int i = 0; i < s.length - 1; i++)
		{
			result.append(s[i]);
			result.append(separator);
		}
		result.append(s[s.length - 1]);
		return result.toString();
	}

	public static String glue(Set<String> words, String separator)
	{
		final StringBuilder result = new StringBuilder();
		int counter = 1;
		for (final String str : words)
		{
			result.append(str);
			if (counter != words.size())
			{
				result.append(separator);
			}
			counter++;
		}
		return result.toString();
	}

	public static String glue(String[] s, String separator)
	{
		final StringBuilder result = new StringBuilder();
		for (int i = 0; i < s.length - 1; i++)
		{
			result.append(s[i]);
			result.append(separator);
		}
		result.append(s[s.length - 1]);
		return result.toString();
	}

	public static String indentParagraph(String s, String indent)
	{
		if (s == null) { return null; }
		s = indent + s;
		s = s.replace("\n", "\n".concat(indent));
		return s;
	}

	public static int[] indicesOf(String sentence, String phrase)
	{
		int i = 0;
		final ArrayList<Integer> occurences = new ArrayList<Integer>();
		while (i < sentence.length())
		{
			final int temp = sentence.indexOf(phrase, i);
			if (temp == -1)
			{
				break;
			}
			else
			{
				occurences.add(temp);
				i = temp + phrase.length();
			}
		}
		if (occurences.size() <= 0) { return new int[0]; }
		final int[] result = new int[occurences.size()];
		for (int j = 0; j < result.length; j++)
		{
			result[j] = occurences.get(j).intValue();
		}
		return result;
	}

	public static boolean isNumeric(String str)
	{
		if (str == null || str.isEmpty()) { return false; }
		final boolean val = str.matches("[+-]?\\d*(\\.\\d+)?");
		if (!val) { return str.equals("0."); }
		return val;
	}

	// METHODS FOR ARABIC LANGUAGE
	public static boolean isPauseMark_AR(char c)
	{
		if (c == 'ۘ' || c == 'ۙ' || c == 'ۚ' || c == 'ۗ' || c == 'ۖ') { return true; }
		return false;
	}

	public static boolean isRightToLeft(String language)
	{
		String[] list;
		if (language.length() == 2)
		{
			list = new String[] { "ar", "fa", "ur", "he", "yi", "ku", "dv",
					"sd" };
		}
		else
		{
			list = new String[] { "Arabic", "Persian", "Urdu", "Hebrew",
					"Yiddish", "کوردی", "Kurdish", "עברית", "اردو", "العربية",
					"فارسی", "سنڌي", "Sindhi", "Divehi" };
		}
		for (final String element : list)
		{
			if (language.equalsIgnoreCase(element)) { return true; }
		}
		return false;
	}

	public static String multiLine(String s, int maxCharsPerLine)
	{
		final char[] digit = s.toCharArray();
		int count = 0;
		for (int i = 0; i < digit.length; i++)
		{
			count++;
			if (count > maxCharsPerLine)
			{
				if (digit[i] == ' ')
				{
					digit[i] = '\n';
					count = 0;
				}
			}
		}
		s = new String(digit);
		return s;
	}

	public static String removeAll(String s, char c)
	{
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			final char ch = s.charAt(i);
			if (ch != c)
			{
				sb.append(ch);
			}
		}
		return sb.toString();
	}

	public static String removeControlCharacters(String s)
	{
		final StringBuilder result = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			final char ch = s.charAt(i);
			if (!Character.isISOControl(ch))
			{
				result.append(ch);
			}
		}
		return result.toString();
	}

	public static String[] removeDiacritics(String s[])
	{
		for (int i = 0; i < s.length; i++)
		{
			s[i] = removeDiacritics(s[i]);
		}
		return s;
	}

	public static String removeDiacritics(String s)
	{
		String result = "";
		final Pattern pattern = Pattern
				.compile("\\p{InCombiningDiacriticalMarks}+");
		result = s.replaceAll("[^\\p{L}\\p{Z}\\p{P}]", "");
		result = pattern.matcher(
				Normalizer.normalize(result, Normalizer.Form.NFD)).replaceAll(
				"");
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < result.length(); i++)
		{
			final char c = result.charAt(i);

			if (c == Arabic.HAMZA_ABOVE.charAt(0)
					|| c == Arabic.HAMZA_BELOW.charAt(0)
					|| c == Arabic.MADDAH.charAt(0) || c == 'ۦ' || c == 'ـ')
			{
			}

			else if (c == Arabic.ALEPH_SUPERSCRIPT.charAt(0)
					|| c == Arabic.ALEPH_WASLA.charAt(0))
			{
				sb.append(Arabic.ALEPH);
			}

			else
			{
				sb.append(c);
			}
		}
		result = null;
		return sb.toString();
	}

	public static ArrayList<String> removeDuplicates(ArrayList<String> s)
	{
		for (int i = 0; i < s.size() - 1; i++)
		{
			for (int j = i + 1; j < s.size(); j++)
			{
				final String a = s.get(i);
				final String b = s.get(j);
				if (a.length() == b.length() && a.equals(b))
				{
					s.remove(j);
					j--;
				}
			}
		}
		return s;
	}

	public static String[] removeEmptyEntriesFromArray(String[] array)
	{
		final ArrayList<String> result = new ArrayList<String>();
		for (int i = 0; i < array.length; i++)
		{
			if (!array[i].isEmpty())
			{
				result.add(array[i]);
			}
		}
		final String[] res = new String[result.size()];
		result.toArray(res);
		return res;
	}

	public static String[] removeEntriesFromArray(String[] array,
			String stringToBeRemoved)
	{
		final ArrayList<String> result = new ArrayList<String>();
		for (int i = 0; i < array.length; i++)
		{
			if (!array[i].equals(stringToBeRemoved))
			{
				result.add(array[i]);
			}
		}
		final String[] res = new String[result.size()];
		result.toArray(res);
		return res;
	}

	public static String[] removeEntriesFromArray(String[] array,
			String[] stringsToBeRemoved)
	{
		for (final String element : stringsToBeRemoved)
		{
			removeEntriesFromArray(array, element);
		}
		return array;
	}

	public static String removeNonTextCharacters(String x)
	{
		x = x.replace(";", "");
		x = x.replace(":", "");
		x = x.replace("-", "");
		x = x.replace("_", "");
		x = x.replace("?", "");
		x = x.replace("!", "");
		x = x.replace(",", "");
		x = x.replace(".", "");
		x = x.replace("&", "");
		x = x.replace("(", "");
		x = x.replace(")", "");
		x = x.replace("<", "");
		x = x.replace(">", "");
		x = x.replace("{", "");
		x = x.replace("}", "");
		x = x.replace("[", "");
		x = x.replace("]", "");
		x = x.replace("\"", "");
		x = x.replace("/", "");
		x = x.replace("’", "");
		x = x.replace("‘", "");
		x = x.replace("–", "");
		x = x.replace("”", "");
		x = x.replace("“", "");
		x = x.replace("*", "");
		x = x.replace("»", "");
		x = x.replace("«", "");
		x = x.replace("'", "");
		x = x.replace("´", "");
		return x;
	}

	public static String[] removePunctuation(String s[])
	{
		for (int i = 0; i < s.length; i++)
		{
			s[i] = removePunctuation(s[i]);
		}
		return removeEmptyEntriesFromArray(s);
	}

	public static String removePunctuation(String s)
	{
		final StringBuilder result = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			if (!Arabic.isQuranicPauseMark(s.charAt(i))
					&& (Character.isLetterOrDigit(s.charAt(i)) || Arabic
							.isValid(s.charAt(i))))
			{
				result.append(s.charAt(i));
			}
		}
		return result.toString();
	}

	public static String removeSpaces(String s)
	{
		return s.replace(" ", "");
	}

	public static String replaceAll(String s, char OLD, char NEW)
	{
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			final char curC = s.charAt(i);
			if (curC != OLD)
			{
				sb.append(curC);
			}
			else
			{
				sb.append(NEW);
			}
		}
		return sb.toString();
	}

	public static String reverseWordOrder(String s)
	{
		final String[] words = splitWords(s);
		final StringBuilder sb = new StringBuilder();
		for (int i = words.length - 1; i >= 0; i--)
		{
			sb.append(words[i]);
			if (i - 1 >= 0)
			{
				sb.append(" ");
			}
		}
		return sb.toString();
	}

	public static String[] reverseWordOrder(String[] s)
	{
		final String result[] = new String[s.length];
		for (int i = 0; i < s.length; i++)
		{
			result[i] = reverseWordOrder(s[i]);
		}
		return result;
	}

	public static String[] splitLines(String s)
	{
		// return s.split("[\n\r\u0085\u2028\u2028]++");
		return s.split("\\r?\\n");
	}

	public static String[] splitStatement(String s, char separator)
	{
		final String[] array = new String[2];
		final int i = s.indexOf(separator);
		if (i == -1)
		{
			array[0] = s;
			return array;
		}
		else
		{
			array[0] = new String(s.substring(0, i));
			array[1] = new String(s.substring(i + 1));
		}
		return array;
	}

	public static String[] splitStatement(String s, String separator)
	{
		final String[] array = new String[2];
		final int i = s.indexOf(separator);
		if (i == -1)
		{
			array[0] = s;
			return array;
		}
		else
		{
			array[0] = new String(s.substring(0, i));
			array[1] = new String(s.substring(i + 1));
		}
		return array;
	}

	public static String[][] splitStatement(String[] s, char separator)
	{
		final String[][] res = new String[2][s.length];
		for (int i = 0; i < s.length; i++)
		{
			res[0][i] = splitStatement(s[i], separator)[0];
			res[1][i] = splitStatement(s[i], separator)[1];
		}
		return res;
	}

	public static String[] splitWords(String s)
	{
		return removeEmptyEntriesFromArray(s.split(" "));
	}

	public static String toASCII(String s)
	{
		return Normalizer.normalize(s, Normalizer.Form.NFD).replaceAll(
				"[^\\p{ASCII}]", "");
	}

	public static String unescapeUnicode(String s)
	{
		final StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
		{
			if (s.charAt(i) == '\\' && s.charAt(i + 1) == 'u')
			{
				final String t = new String(s.substring(i, i + 6));
				final char c = (char) Integer.parseInt(
						new String(t.substring(2)), 16);
				sb.append(c);
				i += 5;
			}
			else
			{
				sb.append(s.charAt(i));
			}
		}
		return sb.toString();
	}

}
